package cn.biplam.common.wrapper.treeFlat.pcTree;

import java.util.ArrayList;
import java.util.List;

import cn.biplam.common.bean.sqlengine.Sql;
import cn.biplam.common.client.Database;
import cn.biplam.common.client.DbResource;
import cn.biplam.common.paramters.SysName;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.KvMap;
import cn.biplam.common.wrapper.sqlresult.SqlResult;
import cn.biplam.common.wrapper.treeFlat.PcNode;
import cn.biplam.common.wrapper.treeFlat.flat.callback.CompareCallback;
import cn.biplam.common.wrapper.treeFlat.pcTree.callback.OperatorTypeCallback;

/**
 *  父子表数据转换成树
 * @author XiaoRuxing Nov 24, 200912:26:04 PM
 * @version 1.0
 */
public class TablePcTree {

	private PcTreeImp tree;
	/** 索引表表名 */
	private String tableName;
	/** 索引表的数据源 */
	private DbResource dbResource;
	/** 当前用户 */
	private String userId = SysName.SysUser;
	
	/** 记录ID字段名 */
	private String nodeIdField;
	/** 父亲ID字段名 */
	private String nodeParentField;
	/** 节点名称字段名 */
	private String nodeNameField;
	/** 业务级别字段名 */
	private String nodeLevelField;
	/** 附加数据字段 */
	private ArrayList<String> addFields;
	/** 排序字段 */
	private ArrayList<String> orderFields;
	
	/**
	 *  构造方法
	 * @param tableName 表名称
	 */
	public TablePcTree(String tableName) throws ErrorMessage{
		this(tableName,null);
	}
	
	/**
	 *  构造方法
	 * @param tableName 表名称
	 */
	public TablePcTree(String tableName,
			DbResource dbReource) throws ErrorMessage{
		//设置表名
		setTableName(tableName,dbReource);
		tree = new PcTreeImp();
	}
	
	/**
	 *  设置索引表表名
	 * @param tableName 表名称
	 * @param dbReource 表数据源(可以为空)
	 * @throws ErrorMessage 表名称为空
	 */
	public void setTableName(String tableName,
			DbResource dbReource) throws ErrorMessage{
		if(tableName==null)throw new ErrorMessage("Table name is null at SimpleIndexPcTree!");
		this.tableName = tableName;
		if(dbReource!=null){
			this.dbResource = dbReource;
		}else{
			this.dbResource = new DbResource();
		}
	}
	
	/**
	 *  设置父子关系数据集字段名称映射<BR>
	 *  记录ID,父亲ID,节点名称和业务级别对应的字段名称
	 * @param nodeIdField     记录ID字段名
	 * @param nodeParentIdField 父亲ID字段名
	 * @param nodeNameField   节点名称字段名
	 * @param nodeLevelField  业务级别字段名(可以为空)
	 */
	public void setFieldMap(String nodeIdField,
			String nodeParentIdField,
			String nodeNameField, 
			String nodeLevelField){
		this.nodeIdField = nodeIdField;
		this.nodeParentField = nodeParentIdField;
		this.nodeNameField = nodeNameField;
		this.nodeLevelField = nodeLevelField;
		this.tree.setFieldMap(nodeIdField, 
				nodeParentIdField, 
				nodeNameField, 
				nodeLevelField);
	}
	
	/**
	 *  放入附加数据字段
	 * @param fields 附加数据字段(可以是一个或者多个字段,此方法可以多次调用)
	 */
	public void putAddFields(String... fields){
		if(this.addFields==null){
			this.addFields = new ArrayList<String>();
		}
		for(String addField:fields){
			this.addFields.add(addField);
		}
	}
	
	/**
	 *  设置排序字段
	 * @param order 排序字段名称
	 */
	public void setOrderFields(String... orderFields){
		if(this.orderFields == null){
			this.orderFields = new ArrayList<String>();
		}
		for(String orderField:orderFields){
			this.orderFields.add(orderField);
		}
	}
	
	/**
	 *  设置节点操作类型字段回调器<BR>
	 *  节点操作类型回调器用于生成节点的操作类型
	 */
	public void setOperatorCallback(OperatorTypeCallback callback){
		this.tree.setOperatorCallback(callback);
	}

	/**
	 * 设置过滤数据列表 
	 * @param filterList 被过滤的节点列表(存储的内容为节点ID)
	 */
	public void setDataFilter(List<String> filterList){
		this.tree.setDataFilter(filterList);
	}

	/**
	 *  设置包含节点列表<BR>
	 *  列表中节点的所有子节点作为当前树的数据,即根节点为列表中的节点(节点数不应过多)<BR>
	 *  与节点过滤条件同时设置时,只能过滤当前节点列表的子节点<BR>
	 * @param includeList 被包含节点的列表
	 */
	public void setInclude(List<String> includeList){
		this.tree.setInclude(includeList);
	}

	/**
	 *  设置包含节点,用于只获取指定节点的子树时<BR>
	 *  列表中节点的所有子节点作为当前树的数据,即根节点为列表中的节点(节点数不应过多)<BR>
	 *  与节点过滤条件同时设置时,只能过滤当前节点列表的子节点<BR>
	 * @param includeList 被包含节点
	 */
	public void setInclude(String includeNode){
		if(includeNode!=null){
			List<String> includeList = new ArrayList<String>();
			includeList.add(includeNode);
			this.setInclude(includeList);
		}
	}

	/**
	 *  设置包含节点列表,<BR>
	 *  列表中节点的所有子节点作为当前树的数据,即根节点为列表中的节点(节点数不应过多)<BR>
	 *  与节点过滤条件同时设置时,只能过滤当前节点列表的子节点<BR>
	 * @param includeList 被包含节点列表,列表为一个数组
	 */
	public void setInclude(String... includeNode){
		List<String> include = new ArrayList<String>();
		for(String node:includeNode){
			include.add(node);
		}
		this.setInclude(include);
	}
	
	/**
	 *  设置根节点条件回调器
	 * @param parentCallback 根节点条件回调器
	 */
	public void setRootNodeCallBack(CompareCallback parentCallback){
		this.tree.setRootNodeCallBack(parentCallback);
	}

	/**
	 * @return 获取当前树
	 * @throws ErrorMessage
	 */
	public PcNode get() throws ErrorMessage {
		//设置数据
		tree.setPcData(getTreeData());
		return this.tree.get();
	}

	public KvMap<String, String> getFieldMap() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 *  获取树数据
	 * @throws ErrorMessage 
	 */
	private SqlResult getTreeData() throws ErrorMessage{
		StringBuilder sp = new StringBuilder();
		sp.append(" select ");
		sp.append(this.nodeIdField);
		sp.append(",");
		sp.append(this.nodeParentField);
		sp.append(",");
		sp.append(this.nodeNameField);
		//查询业务级别字段
		if(this.nodeLevelField!=null){
			sp.append(",");
			sp.append(this.nodeNameField);
		}
		//查询附加字段
		if(this.addFields!=null){
			for(String field:addFields){
				sp.append(",");
				sp.append(field);
			}
		}
		sp.append(" from ");
		sp.append(this.tableName);
		if(this.orderFields!=null){
			sp.append(" order by ");
			int i = 0;
			for(String field:orderFields){
				if(i!=0){
					sp.append(",");
				}
				sp.append(field);
				i++;
			}
		}
		//执行查询
		Database db = new Database(this.dbResource,userId,null);
		try{
			return db.executeSelect(new Sql(sp.toString()));
		}catch (Exception e) {
			StringBuilder erroi = new StringBuilder();
			erroi.append("父子表转换树,数据查询错误:");
			erroi.append(e.getMessage());
			throw new ErrorMessage(erroi.toString());
		}
	}
}
